/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/commons/json/util/FieldInfo.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: FieldInfo.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (Mon, 02 Jul 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.commons.json.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

public class FieldInfo implements Comparable<FieldInfo> {

	private final String name;
	private final Method method;
	private final Field field;

	private final Class<?> fieldClass;
	private final Type fieldType;
	private final Class<?> declaringClass;

	public FieldInfo(String name, Class<?> declaringClass, Class<?> fieldClass, Type fieldType, Method method, Field field) {
		this.name = name;
		this.declaringClass = declaringClass;
		this.fieldClass = fieldClass;
		this.fieldType = fieldType;
		this.method = method;
		this.field = field;

		if (method != null) {
			method.setAccessible(true);
		}

		if (field != null) {
			field.setAccessible(true);
		}
	}

	public FieldInfo(String name, Method method, Field field) {
		this.name = name;
		this.method = method;
		this.field = field;

		if (method != null) {
			method.setAccessible(true);
		}

		if (field != null) {
			field.setAccessible(true);
		}

		if (method != null) {
			if (method.getParameterTypes().length == 1) {
				fieldClass = method.getParameterTypes()[0];
				fieldType = method.getGenericParameterTypes()[0];
			} else {
				fieldClass = method.getReturnType();
				fieldType = method.getGenericReturnType();
			}
			declaringClass = method.getDeclaringClass();
		} else {
			fieldClass = field.getType();
			fieldType = field.getGenericType();
			declaringClass = field.getDeclaringClass();
		}
	}

	@Override
	public String toString() {
		return name;
	}

	public Class<?> getDeclaringClass() {
		return declaringClass;
	}

	public Class<?> getFieldClass() {
		return fieldClass;
	}

	public Type getFieldType() {
		return fieldType;
	}

	public String getName() {
		return name;
	}

	public Method getMethod() {
		return method;
	}

	public Field getField() {
		return field;
	}

	@Override
	public int compareTo(FieldInfo o) {
		return name.compareTo(o.name);
	}

	public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
		T annotation = null;
		if (method != null) {
			annotation = method.getAnnotation(annotationClass);
		}

		if (annotation == null) {
			if (field != null) {
				annotation = field.getAnnotation(annotationClass);
			}
		}

		return annotation;
	}

	public Object get(Object javaObject) throws IllegalAccessException, InvocationTargetException {
		if (method != null) {
			final Object value = method.invoke(javaObject, new Object[0]);
			return value;
		}

		return field.get(javaObject);
	}

	public void set(Object javaObject, Object value) throws IllegalAccessException, InvocationTargetException {
		if (method != null) {
			method.invoke(javaObject, new Object[] { value });
			return;
		}

		field.set(javaObject, value);
	}

	public void setAccessible(boolean flag) throws SecurityException {
		if (method != null) {
			method.setAccessible(flag);
			return;
		}

		field.setAccessible(flag);
	}
}
